package com.fu.sso.service.impl;

import com.fu.core.common.BusinessException;
import com.fu.core.common.ExceptionCode;
import com.fu.core.pojo.User;
import com.fu.core.service.impl.BaseServiceImpl;
import com.fu.core.util.JsonUtil;
import com.fu.core.util.SMSSend;
import com.fu.sso.mapper.UserLoginMapper;
import com.fu.sso.service.UserLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 付龙江
 * @date 2022/2/1 21:06
 */
@Service("userLoginService")
@Transactional(rollbackFor = Throwable.class)
public class UserLoginServiceImpl extends BaseServiceImpl<User> implements UserLoginService {

    /**
     * 短信验证码
     */
    private static final String LOGIN_SMS_USER="login_sms_user:";
    /**
     * 设置token前缀 用于给token加盐
     */
    public static final String TOKEN_USER_REALLY_FRUIT = "token_user_really_fruit:";

    UserLoginMapper userLoginMapper;
    RedisTemplate<String,Object> redisTemplate;
    ValueOperations<String,Object> stringOps;

    @Autowired(required = false)
    public UserLoginServiceImpl(UserLoginMapper userLoginMapper, RedisTemplate<String, Object> redisTemplate) {
        this.userLoginMapper = userLoginMapper;
        this.redisTemplate = redisTemplate;
        stringOps = redisTemplate.opsForValue();
    }

    /**
     * 用户一键登录/注册
     *
     * @param phone 电话
     * @param code  短信验证码
     * @return 返回token
     * @throws Exception 异常处理
     */
    @Override
    public String login(String phone, String code) throws Exception {
        //一键登录
        //1.获取redis服务器存储的验证码
        Object o = stringOps.get(LOGIN_SMS_USER + phone);
        if (o==null){
            throw new BusinessException(ExceptionCode.WRONG_CODE);
        }
        String redisCode = o.toString();
        //验证码失效的判断,如果为空则抛出异常
        if (StringUtils.isEmpty(redisCode)) {
            throw new BusinessException(ExceptionCode.WRONG_CODE);
        }
        // 对验证码做校验, 如果不一致则抛出异常
        if (!redisCode.equals(code)) {
            throw new BusinessException(ExceptionCode.CODE_FAILED);
        }
        //校验完成, 从mysql数据库中查找用户信息
        Example example = new Example(User.class);
        example.createCriteria().andEqualTo("userPhone",phone);
        User user = userLoginMapper.selectOneByExample(example);
        // 删除验证码 防止验证码被多次使用
        redisTemplate.delete(LOGIN_SMS_USER+phone);

        //如果用户不存在, 则匿名注册,匿名格式: "用户:"+phone , 并指定用户状态
        if (user==null){
            //注册时才需要的字段
            user = new User(null,"用户:"+phone,phone,"成都",new Timestamp(System.currentTimeMillis()),
                    null);
        }

        //如果用户存在，获取上次token，如果不为空，移除redis中上一次的登录信息
        String expireToken = user.getToken();
        redisTemplate.delete(TOKEN_USER_REALLY_FRUIT+expireToken);


        //生成token，存储登录信息(json),利用处理后的UUID
        String token = UUID.randomUUID().toString().replace("-", "");

        //处理登录
        // 设置ip,设置token,更新mysql
        user.setToken(token);
        //将设置好的用户信息执行添加或更新
        //执行添加操作
        Integer save = save(user);

        // redis添加token信息和过期时间
        //时间过期策略：pc端2小时  手机端app 1个月，手机端的h5也是2小时
        redisTemplate.opsForValue().set(TOKEN_USER_REALLY_FRUIT+token, JsonUtil.objectToString(user), 2, TimeUnit.HOURS);
        return token;
    }

    /**
     * 根据token
     *
     * @param token token
     * @return 返回用户对象
     * @throws Exception 异常处理
     */
    @Override
    public User checkToken(String token) throws Exception {
        //判断token是否为空
        if (StringUtils.isEmpty(token)){
            throw  new BusinessException(ExceptionCode.NO_TOKEN);
        }
        //进行redisToken拼接
        String key = TOKEN_USER_REALLY_FRUIT+token;

        Object value = redisTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(value)){
            throw  new BusinessException(ExceptionCode.WRONG_TOKEN);
        }
        //延长用户的token有效时间，完成关键的业务，下单/字符
        redisTemplate.expire(key,30,TimeUnit.MINUTES);

        return JsonUtil.stringToObject(value.toString(), User.class);
    }

    /**
     * 短信验证码
     *
     * @param phone 电话
     * @return 返回验证字符串
     */
    @Override
    public String sendLoginSms(String phone){
        String msgCode = SMSSend.getMsgCode();
        System.out.println("++++++++验证码:"+msgCode+"+++++++++");
        //服务器这是失效时间为5分钟
        stringOps.set(LOGIN_SMS_USER+phone,msgCode,5, TimeUnit.MINUTES);
        return msgCode;
    }
}
